/*
	Copyright (c) 2007, ANYwebcam.com Pty Ltd. All rights reserved.

	The software in this package is published under the terms of the BSD style 
	license, a copy of which has been included with this distribution in the 
	license.txt file.
*/
package com.anywebcam.di.component
{
	import com.anywebcam.di.*;
	import com.anywebcam.di.error.*;
	import com.anywebcam.reflection.*;
	
	import flash.errors.IllegalOperationError;

	/**
	 * Provides base functionality for DIComponents, ensuring the key and type are not null, 
	 * and that the implementation type can be cast to the key type if the key is a Class.
	 */
	public class AbstractComponent implements DIComponent
	{
		private var _key:Object;
		private var _type:Class;
		private var _classInfo:ClassInfo;
		
		/**
		 * @param key The Class or String identifier to use for this DIComponent
		 * @param type The Class this DIComponent manages
		 */
		public function AbstractComponent( key:Object, type:Class )
		{
			if( key == null ) throw new ArgumentError('Component key is null.');			
			if( type == null ) throw new ArgumentError('Component type is null.');
			
			_key = key;
			_type = type;
			
			checkTypeCompatibility();
		}
		
		/**
		 * @inheritDoc
		 */
		public function get key():Object
		{
			return _key;
		}
		
		/**
		 * @inheritDoc
		 */
		public function get type():Class
		{
			return _type;
		}
		
		/**
		 * @inheritDoc
		 */
		public function get classInfo():ClassInfo
		{
			if( !_classInfo ) _classInfo = new ClassInfo( _type );
			return _classInfo;
		}
		
		/**
		 * @private
		 * @throws IllegalOperationError
		 */
		public function getInstance( container:DIContainer ):Object
		{
			throw new IllegalOperationError( 'getInstance is not implemented by AbstractComponent' );
			return null;
		}
		
		/**
		 * @throws com.anywebcam.di.error.DIComponentError
		 */
		protected function checkTypeCompatibility():void
		{
			if( key is Class )
			{
				if( (key as Class) != type && classInfo.superClasses.indexOf( key as Class ) == -1 )
				{
					throw new DIComponentError( this, 'Incompatible types, key type:'+ key +', impl type:'+ type );
				}
			}
		}
		
		/**
		 * Returns a nice String describing this DIComponent, its key and its type
		 */
		public function toString():String
		{
			//var className:String = getQualifiedClassName( this );			
			return '['
				//+ className.slice( className.lastIndexOf(':') + 1 ) 
				+'DIComponent'
				+' key='+ key.toString()
				+' type='+ type.toString()
				+']';
		}
	}
}